package com.wzw.springboot.principle.mvc.advice;

import com.wzw.springboot.principle.annotation.MvcExt;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;

/**
 * 对JSON数据格式传输方式添加自定义的拦截
 * <p>
 * WebMvcConfigurationSupport.requestMappingHandlerAdapter()
 * RequestMappingHandlerAdapter.initControllerAdviceCache()
 * ControllerAdviceBean.findAnnotatedBeans()
 * ControllerAdvice controllerAdvice = beanFactory.findAnnotationOnBean(name, ControllerAdvice.class);
 * OrderComparator.sort(adviceBeans);
 *
 * @author Wangzhiwen
 */
// @Order(2) // 执行优先级 或者 实现 Ordered接口
@ControllerAdvice // controller的Bean对象
public class CustomizedRequestBodyAdvice implements RequestBodyAdvice, Ordered {

    /**
     * 是否支持此方法
     *
     * @param methodParameter 反射中的Method包装对象
     * @param targetType      目标类型
     * @param converterType   转换器类型
     * @return true 支持 false 不支持，不支持时不会执行下面的拦截方法
     */
    @Override
    public boolean supports(MethodParameter methodParameter, @Nonnull Type targetType, @Nonnull Class<? extends HttpMessageConverter<?>> converterType) {
        // 是否包含MvcExt注解
        return methodParameter.hasParameterAnnotation(MvcExt.class);
    }

    /**
     * 输入数据的前置处理，如：全局的防止重复提交实现
     *
     * @param inputMessage    可取出Body和Headers
     * @param methodParameter 反射中的Method包装对象
     * @param targetType      目标类型
     * @param converterType   转换器类型
     * @return 返回处理后的输入流
     * @throws IOException 异常
     */
    @Nonnull
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, @Nonnull MethodParameter methodParameter, @Nonnull Type targetType, @Nonnull Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        // 对请求的输入数据进行拦截处理
        InputStream body = inputMessage.getBody();
        HttpHeaders headers = inputMessage.getHeaders();
        // 如果控制了能走到这里，一定不要返回空值。兜底都要返回传进来的HttpInputMessage
        return inputMessage;
    }

    /**
     * 输入数据的后置拦截，这的后置指的是原始JSON数据已被解析成为了具体对象
     *
     * @param body            解析后的具体请求内容对象
     * @param inputMessage    输入流
     * @param methodParameter 反射中的Method包装对象
     * @param targetType      目标类型
     * @param converterType   转换器类型
     * @return 解析后的Body
     */
    @Nonnull
    @Override
    public Object afterBodyRead(@Nonnull Object body, @Nonnull HttpInputMessage inputMessage, @Nonnull MethodParameter methodParameter, @Nonnull Type targetType, @Nonnull Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    /**
     * 处理满足Body为空的情况
     *
     * @param body            解析后的具体请求内容对象
     * @param inputMessage    输入流
     * @param methodParameter 反射中的Method包装对象
     * @param targetType      目标类型
     * @param converterType   转换器类型
     * @return body
     */
    @Override
    public Object handleEmptyBody(Object body, @Nonnull HttpInputMessage inputMessage, @Nonnull MethodParameter methodParameter, @Nonnull Type targetType, @Nonnull Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    /**
     * 优先级
     *
     * @return int
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
